package org.jeecg.modules.iot.middleware.processor.powerOperate;

import org.jeecg.modules.iot.model.modbus.ModbusParams;
import org.jeecg.modules.iot.middleware.processor.JT808Processor;
import org.jeecg.modules.iot.middleware.processor.MessageType;
import org.jeecg.modules.rental.entity.RentalEBike;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;


@Service
public class PowerService {



    @Autowired
    private JT808Processor jt808Processor;


    private static final int MAX_PACKET_SIZE = 240; // 最大数据包大小，除去包头和CRC校验

    public int setPower(RentalEBike car, Boolean powerOffMode, int currentLimit, int timeLimit) {
        // 创建 Modbus 参数对象
        ModbusParams modbusParams = new ModbusParams();

        // 设置从机地址为 0x03 (BMS 的地址)
        modbusParams.setSlaveAddress(0x03);

        // 设置起始寄存器地址为 0xA310
        modbusParams.setStartAddress(0xA310);

        // 设置功能码为写入多个寄存器
        modbusParams.setFunctionCode(ModbusParams.FunctionCode.WRITE_MULTIPLE_REGISTERS);

        // 从 RentalEBike 对象中获取配置值 (假设有相应的 getter 方法)
        int powerMode = 0;
        // 根据断电模式设置 powerMode 的值
        if (powerOffMode == true) {
            powerMode = 1; // 中控通信中断时断电
        } else if (powerOffMode == false) {
            powerMode = 2; // 检测到充电器时断电
        }

        // 获取电流限制值 (假设单位为毫安)
       // int currentLimit = car.getCurrentLimit();

        // 获取时间限制值 (假设单位为秒)
        //int timeLimit = car.getTimeLimit();

        // 设置 0xA310 寄存器的值: 断电模式
        int byte0 = powerMode & 0xFF; // 只使用低两位

        // 设置 0xA311 寄存器的值: 电流限制 (单位为 10mA)
        int byte1 = (currentLimit / 10) & 0xFFFF; // 将毫安转换为 10mA 为单位

        // 设置 0xA312 寄存器的值: 时间限制 (单位为秒)
        int byte2 = timeLimit & 0xFFFF;

        // 设置要写入的值
        modbusParams.setValues(byte0, byte1, byte2);

        // 调用 jt808Processor 发送 Modbus 请求
        Integer seq = jt808Processor.processTransparent(car, MessageType.SETTING_POWER, modbusParams);

        // 如果请求成功，返回 true，否则返回 false
        return seq ;
    }


    public int setContinuousVoltage(RentalEBike car,Boolean isContinuousVoltage){

        // 创建 Modbus 参数对象
        ModbusParams modbusParams = new ModbusParams();

        // 设置从机地址为 0x03 (BMS 的地址)
        modbusParams.setSlaveAddress(0x03);

        // 设置起始寄存器地址为 0xA310
        modbusParams.setStartAddress(0xA200);

        // 设置功能码为写入多个寄存器
        modbusParams.setFunctionCode(ModbusParams.FunctionCode.WRITE_MULTIPLE_REGISTERS);

        // 准备要写入的值
        int byte0 = 0;//电池组健康百分比 不能修改
        /*BMS是否持续输出电压（RW）。
            0：表示不输出
            1：表示输出（默认值）
            */
      /*  int byte1 = 0;*/

        // 根据 isContinuousVoltage 的值设置 byte1
        if (isContinuousVoltage) {
            byte0 = 1& 0xFF; // 持续输出电压
        } else {
              byte0 = 0 & 0xFF; // 不输出电压
        }


        // 设置要写入的值
        modbusParams.setValues(byte0);

        // 调用 jt808Processor 发送 Modbus 请求
        Integer seq = jt808Processor.processTransparent(car, MessageType.SETTING_POWER, modbusParams);

        // 如果请求成功,返回请求序列号,否则返回 0
        return seq;
    }


    public Integer getDeviceSN(RentalEBike car) {
        // 创建 Modbus 参数对象
        ModbusParams modbusParams = new ModbusParams();

        // 设置从机地址为 0x03 (BMS 的地址)
        modbusParams.setSlaveAddress(0x03);

        // 设置起始寄存器地址为 0xA310
        modbusParams.setStartAddress(0xA00D);


        //设置查询寄存器个数
        modbusParams.setRegisterCount(8);

        // 设置功能码为写入多个寄存器
        modbusParams.setFunctionCode(ModbusParams.FunctionCode.READ_HOLDING_REGISTERS);



        // 调用 jt808Processor 发送 Modbus 请求
        Integer seq = jt808Processor.processTransparent(car, MessageType.QUERY_POWER, modbusParams);

        // 如果请求成功，返回 true，否则返回 false
        return seq ;
    }


    public int queryPower(RentalEBike car) {
        // 创建 Modbus 参数对象
        ModbusParams modbusParams = new ModbusParams();

        // 设置从机地址为 0x03 (BMS 的地址)
        modbusParams.setSlaveAddress(0x03);

        // 设置起始寄存器地址为 0xA310
        modbusParams.setStartAddress(0xA200);


        //设置查询寄存器个数
        modbusParams.setRegisterCount(2);

        // 设置功能码为写入多个寄存器
        modbusParams.setFunctionCode(ModbusParams.FunctionCode.READ_HOLDING_REGISTERS);



        // 调用 jt808Processor 发送 Modbus 请求
        Integer seq = jt808Processor.processTransparent(car, MessageType.QUERY_POWER, modbusParams);

        // 如果请求成功，返回 true，否则返回 false
        return seq ;
    }


    public void otaUpgrade(RentalEBike car, byte[] otaData) {
        // 1. 协商 OTA 升级参数
        int negotiatedPacketSize = negotiateOtaParams(car, otaData.length);
        if (negotiatedPacketSize == 0) {
            System.err.println("OTA 协商失败");
            return;
        }

        // 2. 分包发送 OTA 数据
        int packetCount = (int) Math.ceil((double) otaData.length / negotiatedPacketSize);
        for (int i = 0; i < packetCount; i++) {
            int offset = i * negotiatedPacketSize;
            int length = Math.min(negotiatedPacketSize, otaData.length - offset);
            byte[] packetData = Arrays.copyOfRange(otaData, offset, offset + length);

            // 发送分包
            sendOtaPacket(car, i + 1, packetData);
        }
    }

    // 协商 OTA 升级参数
    private int negotiateOtaParams(RentalEBike car, int otaDataSize) {
        // 1. 读取 OTA 信息 (寄存器地址 0x5200，读取 2 个寄存器)
        ModbusParams readParams = new ModbusParams();
        readParams.setSlaveAddress(0x03);
        readParams.setStartAddress(0x5200);
        readParams.setRegisterCount(2);
        readParams.setFunctionCode(ModbusParams.FunctionCode.READ_HOLDING_REGISTERS);

        Integer seq = jt808Processor.processTransparent(car, MessageType.QUERY_OTA_INFO, readParams);
        if (seq == 0) {
            System.err.println("读取 OTA 信息失败");
            return 0;
        }

        // 2. 解析 OTA 信息，获取是否可以升级和最大分包大小
        // ... (等待 Modbus 读取结果，并解析结果)

        // 假设读取结果存储在 response 中
        /*int[] response = { 0, MAX_PACKET_SIZE }; // 模拟读取结果

        if (response[0] != 0) {
            System.err.println("设备不可升级");
            return 0;
        }*/

        int maxPacketSize = 256;

        // 3. 写入协商后的分包大小 (寄存器地址 0x5202，写入 1 个寄存器)
        ModbusParams writeParams = new ModbusParams();
        writeParams.setSlaveAddress(0x03);
        writeParams.setStartAddress(0x5202);
        writeParams.setFunctionCode(ModbusParams.FunctionCode.WRITE_SINGLE_REGISTER);
        writeParams.setValues(maxPacketSize);

        seq = jt808Processor.processTransparent(car, MessageType.SETTING_OTA_PACKET_SIZE, writeParams);
        if (seq == 0) {
            System.err.println("写入分包大小失败");
            return 0;
        }

        return maxPacketSize;
    }

    // 发送 OTA 数据包
    private void sendOtaPacket(RentalEBike car, int packetIndex, byte[] packetData) {
        // 1. 计算 CRC 校验值
        int crc16 = calculateCRC16(packetData);

        // 2. 构建 Modbus 报文
        ModbusParams params = new ModbusParams();
        params.setSlaveAddress(0x03);
        params.setStartAddress(0x5204);
        params.setFunctionCode(ModbusParams.FunctionCode.WRITE_MULTIPLE_REGISTERS);
        // 将包序号和数据合并到一起
        byte[] data = new byte[packetData.length + 2];
        data[0] = (byte) (packetIndex >> 8); // 包序号高位
        data[1] = (byte) packetIndex; // 包序号低位
        System.arraycopy(packetData, 0, data, 2, packetData.length);
        params.setValues(data[0],data[1]);

        // 3. 发送 Modbus 报文
        Integer seq = jt808Processor.processTransparent(car, MessageType.SEND_OTA_PACKET, params);
        if (seq == 0) {
            System.err.println("发送 OTA 数据包 " + packetIndex + " 失败");
            // ... (错误处理，例如重试)
        }

        // 4. 校验 CRC
        // ... (等待 Modbus 写入结果，并校验 CRC)
    }

    private int calculateCRC16(byte[] data) {
        int crc = 0xFFFF; // 初始化 CRC 值

        for (byte b : data) {
            crc ^= (b & 0xFF) << 8; // 将字节与 CRC 值异或

            for (int i = 0; i < 8; i++) {
                if ((crc & 0x8000) != 0) {
                    crc = (crc << 1) ^ 0x1021; // 如果最高位为 1，则左移并与多项式异或
                } else {
                    crc <<= 1; // 否则直接左移
                }
            }
        }

        return crc & 0xFFFF; // 返回 CRC16 校验值
    }

  /*  public static void main(String[] args) {
        RentalEBike car=new RentalEBike();
        car.setPhone("583078541427");
        car.setCarCode("869583078541427");
        PowerService powerService=new PowerService();
        powerService.setPower(car,true,1,20);
    }*/
}
